/*
 * Copyright (C) 2008
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.sca4idea.util;

import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.xml.XmlDocument;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.googlecode.sca4idea.providers.SCAProvider;
import com.googlecode.sca4idea.psi.SCAComponentTagPsiElement;
import com.googlecode.sca4idea.psi.SCAUnknownComponentTagPsiElement;
import com.googlecode.sca4idea.facet.SCAFacet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.HashMap;
import java.util.Map;

/**
 * Resolver for detecting components available within a given composite file.
 *
 * @author paul.jones
 */
public final class ComponentResolver {
    @NotNull
    public static Map<String, SCAComponentTagPsiElement> getComponents(XmlFile xmlFile) {
        Map<String, SCAComponentTagPsiElement> result = new HashMap<String, SCAComponentTagPsiElement>();
        XmlDocument doc = xmlFile.getDocument();
        if (doc == null) return result;
        XmlTag rootTag = doc.getRootTag();
        if (rootTag == null) return result;

        XmlTag[] components = rootTag.findSubTags("component");
        for (XmlTag component : components) {
            String nameValue = component.getAttributeValue("name");

            if (StringUtil.isNotEmpty(nameValue)) {
                result.put(nameValue, getSCAComponentInstance(component));
            }
        }

        return result;
    }

    @NotNull
    public static Map<String, XmlTag> getPromotedServices(XmlFile file) {
        return getPromotionTags(file, "service", true);
    }

    @NotNull
    public static Map<String, XmlTag> getPromotedReferences(XmlFile xmlFile, boolean requirePromote) {
        return getPromotionTags(xmlFile, "reference", requirePromote);
    }

    @NotNull
    public static Map<String, XmlTag> getPromotedProperties(XmlFile xmlFile, boolean requirePromote) {
        return getPromotionTags(xmlFile, "property", requirePromote);
    }

    public static String getTargetComponentName(String targetStr) {
        if (targetStr.indexOf('/') == -1) {
            return targetStr;
        }

        return targetStr.substring(0, targetStr.indexOf('/'));
    }

    public static String getTargetServiceInterfaceName(String targetStr) {
        if (targetStr.indexOf('/') == -1) {
            return null;
        }

        return targetStr.substring(targetStr.indexOf('/') + 1);
    }

    public static String getTargetReferenceName(String targetStr) {
        if (targetStr.indexOf('/') == -1) {
            return null;
        }

        return targetStr.substring(targetStr.indexOf('/') + 1);
    }

    public static SCAComponentTagPsiElement getSCAComponentInstance(XmlTag componentTag) {
        SCAComponentTagPsiElement scaTag = SCAFacet.getPSIElementForTag(componentTag);
        if (scaTag != null) {
            return scaTag;
        }
        
        return new SCAUnknownComponentTagPsiElement(componentTag);
    }

    public static TextRange[] splitSlashedReference(String s, TextRange all) {
        String text = s.substring(all.getStartOffset() -1, all.getEndOffset() - 1);
        int slashPos = text.indexOf('/');

        if (slashPos == -1) {
            return new TextRange[] { all };
        } else {
            return new TextRange[] {
                    new TextRange(all.getStartOffset(), all.getStartOffset() + slashPos),
                    new TextRange(all.getStartOffset() + slashPos + 1, all.getEndOffset())
            };
        }
    }

    @NotNull
    private static Map<String, XmlTag> getPromotionTags(XmlFile file, String tagName, boolean requirePromote) {
        Map<String, XmlTag> result = new HashMap<String, XmlTag>();
        XmlDocument doc = file.getDocument();
        if (doc == null) return result;
        XmlTag rootTag = doc.getRootTag();
        if (rootTag == null) return result;

        XmlTag[] promotions = rootTag.findSubTags(tagName);
        for (XmlTag promotion : promotions) {
            String nameValue = promotion.getAttributeValue("name");
            String promoteValue = promotion.getAttributeValue("promote");

            if (StringUtil.isNotEmpty(nameValue) && (!requirePromote || StringUtil.isNotEmpty(promoteValue))) {
                result.put(nameValue, promotion);
            }
        }

        return result;
    }
}
